import sys
import threading
import multiprocessing

sys.path.append("..")
try:
    from CoreSim.Unit import *
    from CoreSim.Event import *
    from CoreSim.Simulator import *
    from CoreSim.SchedulerHybrid import *
except:
    raise


def run_simulation(_numToRs, _numHosts, _numLinks, _numSLinks, _link_ss_Bw, _load, _time, _workloadCDF, _workloadType,
                   _scheduler, _interval, _adjust_delay, _sample_enable, _sample_interval, _round_i):
    # STEP1: topology
    s_topoFileName = "topo_%sToRs_%sHosts_%sLinks_%sSLinks_static.txt" \
                     % (_numToRs, _numHosts, _numLinks, _numSLinks)
    d_topoFileName = "topo_%sToRs_%sHosts_%sLinks_%sSLinks_dynamic.txt" \
                     % (_numToRs, _numHosts, _numLinks, _numSLinks)


    # STEP2: traffic workload
    cdfFileName = "cdf/{}_CDF.txt".format(_workloadCDF)
    flowsFileName = "%sToR_%sHosts_%sLinks_%sload_%stime_%s_%s_%s.txt" \
                    % (_numToRs, _numHosts, _numLinks, _load, _time, _workloadCDF, _workloadType, _round_i)
    flowsFileName = flowsDir + flowsFileName

    print (flowsFileName)
    if not os.path.exists(inDir + flowsDir):
        os.makedirs(inDir + flowsDir)
    if not os.path.isfile(inDir + flowsFileName):
        print ("generate workload")
        run_cmd = "./Input/fct numHosts " + str(_numHosts) + " numLinks " + str(_numLinks) \
                  + " numSwitches " + str(_numToRs) + " link_sh_Bw " + str(_link_ss_Bw) \
                  + " link_ss_Bw " + str(_link_ss_Bw) + " load " + str(_load) + " randomSeed " \
                  + str(randomSeed) + " cdfFileName " + inDir + cdfFileName + " flowsFileName " + inDir \
                  + flowsFileName + " FLOW_LAUNCH_END_TIME " + str(_time) + " trafficPattern " + _workloadType

        os.system(run_cmd)

    # STEP2: new simulator
    simulator = Simulator()

    # STEP3: new scheduler
    simulator.AssignSdnScheduler(Scheduler=SchedulerHybrid(_numLinks, _numSLinks, _numHosts,
                                                           _numToRs, _link_ss_Bw, _scheduler, k=2),
                                 args=("CDF", flowsFileName))

    simulator.sched.interval = _interval
    simulator.sched.adjust_delay = _adjust_delay
    simulator.sched.InitialTopology(flowsDir, s_topoFileName, d_topoFileName)

    # STEP4: enable hybrid scheduler
    if _scheduler != "Jelly":
        event = UpdateTopologyEvent(_interval)  # reconfigure event
        simulator.eventQueue.push(event, event.time)

    # STEP5: enable sample event
    if _sample_enable:
        if not os.path.exists(outDir + flowsDir):
            os.makedirs(outDir + flowsDir)
        sampleFileName = outDir + flowsDir + "%s_%sToR_%sHosts_%sLinks_%sload_%stime_%s_%s_%s_sample" \
                                             ".txt" % (_scheduler, _numToRs, _numHosts, _numLinks, _load,
                                                       _time, _workloadCDF, _workloadType, _round_i)
        print (sampleFileName)
        sampleFile = open(sampleFileName, "w")
        event = SampleEvent(_sample_interval, _sample_interval, sampleFile)  # reconfigure event
        simulator.eventQueue.push(event, event.time)

    # STEP6: start simulation
    simulator.Run()
    simulator.sched.PrintFlows()
    sampleFile.close()

if __name__ == "__main__":

    # topology parameters
    numToRs = 64
    numHosts = 10
    numLinks = 10
    numSLinks = 2  # static links
    link_sh_Bw = 10.0 * Gb
    link_ss_Bw = 10.0 * Gb

    # workload parameters
    flowsDir = ""
    load = 0.6
    time = 2
    randomSeed = 1
    workloadCDFs = ["DCTCP", "VL2"]
    workloadTypes = ["random", "permutation", "cluster"]

    # scheduler parameters
    schedulers = ["Jelly", "OSA", "Detour", "OvS"]
    interval = 10.0e-1  # Periodicity get the traffic matrix (Seconds)
    adjust_delay = 10.0e-3  # Circuit switching time (Seconds)
    sample_enable = True  #
    sample_interval = 1.0e-4  # (Seconds)

    # running rounds
    iteration_a = 0
    iteration_b = 1

    # -------------------------------------------------
    # test case 1
    if True:
        # topology
        numToRs = 64
        numHosts = 16
        numLinks = 10
        numSLinks = 2

        # workloads
        flowsDir = "case1/"
        load = 0.6
        time = 1
        randomSeed = 1
        workloadCDFs = ["VL2"]
        workloadTypes = ["random"]

        # scheduler
        schedulers = ['Detour', 'Jelly', 'OSA', 'OvS']
        interval = 0.1  # Periodicity get the traffic matrix (Seconds)
        adjust_delay = 10.0e-3  # Circuit switching time (Seconds) 10ms
        sample_enable = True  #
        sample_interval = 1.0e-3  # sample network throughput

    compile_cmd = "g++ ./Input/fct.cc -o ./Input/fct -std=c++11"
    os.system(compile_cmd)

    # multi process
    threads = []
    semaphore = threading.Semaphore(multiprocessing.cpu_count())

    for round_i in xrange(iteration_a, iteration_b):
        for workloadCDF in workloadCDFs:
            for workloadType in workloadTypes:
                for scheduler in schedulers:

                    threads.append(threading.Thread(target=run_simulation,
                                                    args=(numToRs, numHosts, numLinks, numSLinks, link_ss_Bw,
                                                          load, time, workloadCDF, workloadType, scheduler, interval,
                                                          adjust_delay, sample_enable, sample_interval, round_i)))

    print ("\n")
    [thread.start() for thread in threads]
    [thread.join() for thread in threads]
    print ("finished", len(threads), "experiments")
